﻿// <copyright file="UserProvider.cs" company="Ecole Normale Supérieure">
// Released under GPLv2
// </copyright>
// <summary>Contains the UserProvider provider</summary>

namespace Sqwarea.Persistence.Azure
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Lokad;
    using Lokad.Cloud.Storage;

    /// <summary>
    /// Provider for storing user-related data on the cloud
    /// </summary>
    public class UserProvider : IUserProvider
    {
        /// <summary>
        /// Name of the container storing Users.
        /// </summary>
        public const string UserBlobContainerName = "sqwarea-user-container";

        /// <summary>
        /// blob provider
        /// </summary>
        private readonly IBlobStorageProvider _blobProvider;

        /// <summary>
        /// Initializes a new instance of the UserProvider class.
        /// </summary>
        /// <param name="blobProvider"> a blob provider</param>
        [CLSCompliantAttribute(false)]
        public UserProvider(IBlobStorageProvider blobProvider)
        {
            if (null == blobProvider)
            {
                throw new ArgumentNullException("blobProvider", "blobProvider must not be null");
            }

            _blobProvider = blobProvider;
            ////this._blobProvider.CreateContainer(BlobName.GetContainerName<UserName>());
        }

        /// <summary>
        /// returns the user, given its OpenId.
        /// </summary>
        /// <param name="openId">The openId you want the user</param>
        /// <returns>The user you gave the openid.</returns>
        public User GetUserByOpenId(string openId)
        {
            Maybe<User> user = _blobProvider.GetBlob(new UserName(openId));
            if (user.HasValue)
            {
                if (user.Value.RemembranceSessions == null)
                {
                    user.Value.RemembranceSessions = new Dictionary<string, RemembranceSession>();
                }

                return user.Value;
            }
            
            throw new InvalidOperationException("No User was found with this Id");
        }

        /// <summary>
        /// Returns a list of users of the given openIds.
        /// TODO : Improve this
        /// </summary>
        /// <param name="openIds">The list of openId</param>
        /// <returns>The list of users</returns>
        public IEnumerable<User> GetUsersByOpenId(IEnumerable<string> openIds)
        {
            return openIds.Select(openId => GetUserByOpenId(openId));
        }

        /// <summary>
        /// returns whether or not the user exists.
        /// </summary>
        /// <param name="openId">The openId</param>
        /// <returns>Whether or not the user exists</returns>
        public bool UserExists(string openId)
        {
            if (string.IsNullOrEmpty(openId))
            {
                return false;
            }

            Maybe<User> user = _blobProvider.GetBlob(new UserName(openId));
            return user.HasValue;
        }

        /// <summary>
        /// Delete a user.
        /// </summary>
        /// <param name="user">The user to delete</param>
        public void DeleteUser(User user)
        {
            _blobProvider.DeleteBlob(new UserName(user.OpenId));
        }

        /// <summary>
        /// Saves the user on the cloud.
        /// </summary>
        /// <param name="user">The user you want to update parameters.</param>
        public void UpdateUser(User user)
        {
            _blobProvider.PutBlob(new UserName(user.OpenId), user);
        }

        /// <summary>
        /// Class enabling to select a user on the blob storage (kind of strong typed key)
        /// </summary>
        private class UserName : BlobName<User>
        {
            /// <summary>
            /// Gets the userId, which will be the name of the blob
            /// </summary>
            [Rank(0)]
            public readonly string UserId;

            /// <summary>
            /// Initializes a new instance of the UserName class.
            /// </summary>
            /// <param name="userId">userId of the user</param>
            public UserName(string userId)
            {
                UserId = Tools.GetMD5Hash(userId);
            }

            /// <summary>
            /// Name of blob container
            /// </summary>
            public override string ContainerName
            {
                get { return UserBlobContainerName; }
            }
        }
    }
}
